#pragma once 
#include <queue>
#include <iostream>
#include <pthread.h>
#include <mutex>

template<class T>
class BlockQueue
{
public:

BlockQueue(int cap)
:_cap(cap)
{
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_consumer_cond,nullptr);
    pthread_cond_init(&_productor_cond,nullptr);
   std::cout<<"BlockQueue()"<<std::endl;
}
bool isfull()
{
    return _q.size()==_cap;
}
bool isempty()
{
    return _q.size()==0;
}
void push(T&in)
{
    pthread_mutex_lock(&_mutex);
    while(isfull())
    {
        //满
    pthread_cond_wait(&_productor_cond,&_mutex);
    }
    _q.push(in);
    pthread_cond_signal(&_consumer_cond);
    pthread_mutex_unlock(&_mutex);
}

void pop(T*out)
{
    pthread_mutex_lock(&_mutex);
    while(isempty())
    {
        //kong
    pthread_cond_wait(&_consumer_cond,&_mutex);
    }
    *out=_q.front();
    _q.pop();
    pthread_cond_signal(&_productor_cond);
    pthread_mutex_unlock(&_mutex);
} 

~BlockQueue()
{
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_consumer_cond);
    pthread_cond_destroy(&_productor_cond);

    std::cout<<"~BlockQueue()"<<std::endl;
}

private:
std::queue<T> _q;
int _cap;
pthread_mutex_t _mutex;
pthread_cond_t _consumer_cond;
pthread_cond_t _productor_cond;

};
